package com.sysolve.common;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.cfg.Configuration;
import org.hibernate.tool.hbm2ddl.SchemaExport;
import org.hibernate.tool.hbm2ddl.SchemaUpdate;

/**
 * Configures and provides access to Hibernate sessions, tied to the current thread of execution.  Follows the Thread Local Session pattern, see  {@link  http://hibernate.org/42.html } .
 */
public class HibernateSessionFactory {

    /** 
     * Location of hibernate.cfg.xml file.
     * Location should be on the classpath as Hibernate uses  
     * #resourceAsStream style lookup for its configuration file. 
     * The default classpath location of the hibernate config file is 
     * in the default package. Use #setConfigFile() to update 
     * the location of the configuration file for the current session.   
     */
    private static String CONFIG_FILE_LOCATION = "/hibernate.cfg.xml";
    private static String configFile = CONFIG_FILE_LOCATION;
    
    private static Configuration configuration = null;
    private static org.hibernate.SessionFactory sessionFactory = buildSessionFactory();
    
	private static final ThreadLocal<Session> threadLocal = new ThreadLocal<Session>();

    /**
	 * @uml.property  name="sessions"
	 * @uml.associationEnd  qualifier="key:java.lang.Object java.util.Date"
	 */
    public static Map<Session, Date> sessions = new HashMap<Session, Date>();
    
    private HibernateSessionFactory() {
    }
	
	/**
     * Returns the ThreadLocal Session instance.  Lazy initialize
     * the <code>SessionFactory</code> if needed.
     *
     *  @return Session
     *  @throws HibernateException
     */
    public static Session getSession() throws HibernateException {
        Session session = (Session) threadLocal.get();
               
		if (session == null || !session.isOpen()) {
			session = (sessionFactory != null) ? sessionFactory.openSession() : null;
			threadLocal.set(session);
			sessions.put(session, new Date());
		}

        return session;
    }
    
	/**
     *  Close the single hibernate session instance.
     *
     *  @throws HibernateException
     */
    public static void closeSession() throws HibernateException {
        Session session = (Session) threadLocal.get();
        threadLocal.set(null);

        if (session != null) {
        	session.close();
        	sessions.remove(session);
        }
    }

	/**
     *  build hibernate session factory
     *
     */
	private synchronized static org.hibernate.SessionFactory buildSessionFactory() {
		try {
			configuration = new Configuration();
			configuration.configure(configFile);
			return configuration.buildSessionFactory();
		} catch (Exception e) {
			System.err
					.println("%%%% Error Creating SessionFactory %%%%");
			e.printStackTrace();
			return null;
		}
	}
	
	public synchronized static void rebuildSessionFactory() {
		if (sessionFactory!=null) sessionFactory.close();
		sessionFactory = buildSessionFactory();
	}

	/**
	 * return session factory
	 * @uml.property  name="sessionFactory"
	 */
	public static org.hibernate.SessionFactory getSessionFactory() {
		return sessionFactory;
	}


}